class GameWorld {
  final GameEntity root;
  final Map<String, GameEntity> idEntities;
  final Map<String, Set<GameEntity>> taggedEntities;
  final Map<String, Set<GameEntity>> dataEntities;

  GameWorld() : root = new GameEntity(),
                idEntities = new Map<String, GameEntity>(),
                taggedEntities = new Map<String, Set<GameEntity>>(),
                dataEntities = new Map<String, Set<GameEntity>>(){
  }

  CompositeEntities query(String selectors) {
    return new CompositeEntities();
  }
  
  void _onIDChanged(GameEntity entity, String old) {
    if (old != null) {
      if (idEntities[old] === entity) {
        idEntities.remove(old);
      }
    }
    
    if (entity.id != null)
      idEntities[entity.id] = entity;
  }

  void _onTagAdded(GameEntity entity, String tag) => _onDataOrTagRemoved(taggedEntities, entity, tag);
  void _onTagRemoved(GameEntity entity, String tag) => _onDataOrTagRemoved(taggedEntities, entity, tag);
  void _onDataAdded(GameEntity entity, String tag) => _onDataOrTagRemoved(dataEntities, entity, tag);
  void _onDataRemoved(GameEntity entity, String tag) => _onDataOrTagRemoved(dataEntities, entity, tag);
  static _onDataOrTagAdded(Map<String, Set<GameEntity>> map, GameEntity entity, String key) {
    final l = map[key];
    if (l != null)
      l.add(entity);
    else
      map[key] = new Set<GameEntity>.from([entity]);
  }
  
  static _onDataOrTagRemoved(Map<String, Set<GameEntity>> map, GameEntity entity, String key) {
    final l = map[key];
    if (l != null)
      l.remove(entity);
  }
}

GameWorld _world;
GameWorld get world() => _world;